package nyc3d;

import com.jme3.light.Light;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.plugins.blender.objects.Properties;

/**
 * A utility class for the creation, modification, and debugging of spatials (Nodes and Geometries)
 */
public class NodeInspector {
    /** 
     * Builds a node from a .blend file
     * @param n node from Blender file
     * @return node to use internally
     */
    public static Node buildNode(Node rootNode, Node n){
        Node node = new Node(n.getName());
        
        //Add lights
        for (Light l: n.getLocalLightList())
            rootNode.getLocalLightList().add(l);
        
        
        Node streetlights = new Node("Streetlights"); 
        Node roads = new Node("Roads");
        
        //Process roads
        
        //Add "0" through "9"
        for(int i = 0; i <= 9; i++)
            roads.attachChild(new Node(String.valueOf(i)));
        
        //Add "A" through "Z"
        for(int i = (int)'A'; i <= (int)'Z'; i++)
            roads.attachChild(new Node(String.valueOf((char)i)));        
        
        for(int i = 0; i < n.getChildren().size(); i++){       
            if (n.getChild(i).getName().startsWith("R_")){
                
                Node parentNode = new Node();
                char start = n.getChild(i).getName().charAt(2);
                start = Character.toUpperCase(start);
                if (Character.isDigit(start)){
                    parentNode = (Node)roads.getChild((int) start);
                }
                else if (Character.getType(start) == Character.UPPERCASE_LETTER){                  
                    parentNode = (Node)roads.getChild(((int) start) - 55);
                }
                else
                    throw new IllegalArgumentException(n.getChild(i).getName().substring(2) + " does not start with a letter or number!");
                               
                int loc = getIndexOfMatchingName(parentNode, ((Properties)n.getChild(i).getUserData("properties")).findValue("roadName") + "_" + ((Properties)n.getChild(i).getUserData("properties")).findValue("borough"));
                if (loc == -1){
                    Node streetNode = new Node(((Properties)n.getChild(i).getUserData("properties")).findValue("roadName") + "_" + ((Properties)n.getChild(i).getUserData("properties")).findValue("borough"));
                    copySpatial(streetNode, n.getChild(i));
                    copySpatial(parentNode, streetNode);
                    
                } else{
                copySpatial((Node)parentNode.getChild(loc), n.getChild(i));
                }
                
                
                //if (((Node)roads.getChild(n.getChild(i).getName().substring(2,3).toUpperCase())).hasChild(roads))
            }
            
            //Process streetlights
            if (n.getChild(i).getName().startsWith("Streetlight")){
                copySpatial(streetlights, n.getChild(i));
            }
            
        }
        
        node.attachChild(streetlights);
        
        
        
      
        
        node.attachChild(roads);
        
        return node;
    }
    
    /**
     * Return the index of a child node or geometry  that matches a given name . This does not 
     * check for equality, simply whether a node/geometry exists with the same name.
     * @param node the node to check
     * @param childName the name of the node or geometry to check
     * @return 
     */
    public static int getIndexOfMatchingName(Node node, String childName){      
        for(int i = 0; i < node.getChildren().size(); i++){
            if (node.getChild(i).getName().equals(childName)){
                return i;
            }
        }
        
        return -1;
    }
    
    /** 
     * Copies s and all of its children as a child of parentNode
     * @param parentNode the parent node of s and its children
     * @param s the spatial to copy
     */
    public static void copySpatial(Node parentNode, Spatial s){
        parentNode.attachChild(s.clone());
    }
    
    /** 
     * Prints out an organized listing of a given spatial, including all of its children
     * @param level amount of tabs for the given spatial (usually 0 if called explicitly)
     * @param n the spatial to inspect
     */
    public static void inspectNode(int level, Spatial n){
        for(int j = 1; j <= level; j++){
                    System.out.print("\t");             
        }
        System.out.print(n.getName());
        if (n.getClass().getName().equals("com.jme3.scene.Geometry") || (n.getClass().getName().equals("com.jme3.scene.Node") && ((Node)n).getChildren().isEmpty())){
            System.out.println();
            return;
        }
        else{ //n is a Node with children
            for(int i = 0; i < ((Node)n).getLocalLightList().size(); i++){
                System.out.print("\t\"" + ((Node)n).getLocalLightList().get(i).getName() + "\"");
            }
            System.out.println();
            
            for(int i = 0; i < ((Node)n).getChildren().size(); i++){
                    inspectNode(level+1, ((Node)n).getChild(i));
                    
                
            }          
        }                                
    }
}